package com.guchenbo.example.future;

import com.google.common.util.concurrent.Uninterruptibles;
import com.guchenbo.example.thread.GcbThreadFactory;

import java.util.concurrent.*;

public class CompletableFutureTest {

    private static ExecutorService executor = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFutureTest demo = new CompletableFutureTest();
        //        demo.test1();
        //        demo.test2();
        //        demo.test3();
        //        demo.test4();
        //        demo.test5();
        demo.test6();
        //        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        //            try {
        //                Thread.sleep(5000);
        //            } catch (InterruptedException e) {
        //                throw new RuntimeException(e);
        //            }
        //            return "word";
        //        });
        //        System.out.println(future.get());
        //
        //        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> System.out.println("111"));
        //        System.out.println(future2.get());

    }

    private void test6() {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            String s = "a";
            System.out.println(s + " in " + Thread.currentThread());
            return s;
        }, executor).thenApplyAsync((s) -> {
            s += "b";
            System.out.println(s + " in " + Thread.currentThread());
            Uninterruptibles.sleepUninterruptibly(3,TimeUnit.SECONDS);
            Integer.parseInt(s);
            return s;
        }, executor).exceptionally((e) -> {
            e.printStackTrace();
            return "error";
        });
        System.out.println(future1.join());
        try {
            System.out.println(future1.get());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    private void test5() {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            String s = "a";
            System.out.println(s + " in " + Thread.currentThread());
            return s;
        }, executor).thenApplyAsync((s) -> {
            s += "b";
            System.out.println(s + " in " + Thread.currentThread());
            return s;
        }, executor);
        future1.thenAccept(s -> {
            System.out.println(s + " in " + Thread.currentThread());
        }).thenRunAsync(() -> {
            System.out.println("d");
        }).thenAccept((s) -> {
            System.out.println(s);
        });

    }

    private void test4() {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            String s = "a";
            System.out.println(s + " in " + Thread.currentThread());
            Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
            return s;
        }, executor).thenApplyAsync((s) -> {
            s += "b";
            Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
            System.out.println(s + " in " + Thread.currentThread());
            return s;
        }, executor).thenApplyAsync((s) -> {
            s += "c";
            System.out.println(s + " in " + Thread.currentThread());
            return s;
        }, executor).thenApplyAsync((s) -> {
            s += "d";
            System.out.println(s + " in " + Thread.currentThread());
            return s;
        }, executor).thenApplyAsync((s) -> {
            Integer.parseInt(s);
            return "";
        }, executor).exceptionally(e -> {
            //            e.printStackTrace();
            return "error";
        });
        try {
            System.out.println(future1.get());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    private void test3() {
        GcbThreadFactory.create("t1", () -> {
            CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
                String s = "a";
                System.out.println(s + " in " + Thread.currentThread());
                //                Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
                return s;
            }, executor).thenApply((s) -> {
                s += "b";
                //            Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
                System.out.println(s + " in " + Thread.currentThread());
                return s;
            }).thenApply((s) -> {
                s += "c";
                System.out.println(s + " in " + Thread.currentThread());
                return s;
            }).thenApply((s) -> {
                s += "d";
                System.out.println(s + " in " + Thread.currentThread());
                return s;
            }).thenApply((s) -> {
                Integer.parseInt(s);
                return "";
            }).exceptionally(e -> {
                //            e.printStackTrace();
                return "error";
            });
            try {
                System.out.println(future1.get());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ExecutionException e) {
                throw new RuntimeException(e);
            }
        }).start();
    }

    /**
     * main调用thenApply时候Future还没完成，所以使用前面Future的线程池
     */
    private void test2() {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            String s = "a";
            System.out.println(s + " in " + Thread.currentThread());
            Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
            return s;
        }, executor).thenApply((s) -> {
            s += "b";
            //            Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
            System.out.println(s + " in " + Thread.currentThread());
            return s;
        }).thenApply((s) -> {
            s += "c";
            System.out.println(s + " in " + Thread.currentThread());
            return s;
        }).thenApply((s) -> {
            s += "d";
            System.out.println(s + " in " + Thread.currentThread());
            return s;
        }).thenApply((s) -> {
            Integer.parseInt(s);
            return "";
        }).exceptionally(e -> {
            //            e.printStackTrace();
            return "error";
        });
        try {
            System.out.println(future1.get());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * thenApplyAsync 默认使用公共的ForkJoinPool的公共线程池
     */
    private void test1() {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            String s = "a";
            System.out.println(s + " in " + Thread.currentThread());
            Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
            return s;
        }, executor).thenApplyAsync((s) -> {
            s += "b";
            Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
            System.out.println(s + " in " + Thread.currentThread());
            return s;
        }).thenApplyAsync((s) -> {
            s += "c";
            System.out.println(s + " in " + Thread.currentThread());
            return s;
        }).thenApplyAsync((s) -> {
            s += "d";
            System.out.println(s + " in " + Thread.currentThread());
            return s;
        }).thenApplyAsync((s) -> {
            Integer.parseInt(s);
            return "";
        }).exceptionally(e -> {
            //            e.printStackTrace();
            return "error";
        });
        try {
            System.out.println(future1.get());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

}
